#define LOG_TAG "SharedBufferServer"

#include <utils/Log.h>
#include <cutils/ashmem.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>

#include "../common/ISharedBuffer.h"

class SharedBufferService : public BnSharedBuffer {
public:
    SharedBufferService() {}

    virtual ~SharedBufferService() {
        mBuffer = nullptr;
    }

public:
    static void instantiate() {
        status_t status = defaultServiceManager()->addService(String16(SHARED_BUFFER_SERVICE),
                                                              new SharedBufferService());
        if (status == OK) {
            ALOGD("Register SharedBufferService OK.");
        } else {
            ALOGD("Register SharedBufferService failed.");
        }
    }

    virtual sp<SyncBuffer> createBuffer(size_t size, const char *name) {
        if (mBuffer == nullptr) {
            mBuffer = new SyncBuffer(sizeof(BufferData) + size, name);
        }

        return mBuffer;
    }

    status_t commitBuffer(bool /*async*/) {
        return consumeBuffer();
    }

    status_t releaseBuffer() {
        mBuffer = nullptr;
        return OK;
    }

    status_t consumeBuffer() {
        if (mBuffer != nullptr) {
            ALOGD("Server: buffer locked");
            mBuffer->lock();
            ALOGD("Server: buffer locked ok");

            size_t len;
            auto data = buffer_data_cast<BufferData *>(mBuffer->addr(&len));

            if (!data) {
                return NO_MEMORY;
            }

            int payloadSize = data->payload_size;
            if (payloadSize <= 0) {
                return NOT_ENOUGH_DATA;
            }

            char *payload = new char[payloadSize];
            memcpy(payload, data->payload, payloadSize);

            ALOGD("typedef struct {\n"
                  "    uint32_t int1 = %x;\n"
                  "    uint32_t int2 = %x;\n"
                  "    uint32_t int3 = %x;\n"
                  "    uint32_t int4 = %x;\n"
                  "    uint32_t payload_size = %d;\n"
                  "    char payload = %s;\n"
                  "} BufferData;",
                  data->int1, data->int2, data->int3,
                  data->int4, data->payload_size, payload);

            free(payload);

            ALOGD("Server: sleep 10s to unlock");
            sleep(10);
            mBuffer->unlock();
            ALOGD("Server: buffer unlocked");
        } else {
            ALOGE("mMemory == null");
            return NO_MEMORY;
        }

        return OK;
    }

private:
    sp<SyncBuffer> mBuffer = nullptr;
};

int main(int /*argc*/, char ** /*argv*/) {
    SharedBufferService::instantiate();

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

    return 0;
}
